#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""DocString
Script en Python para chequer el número de servidores de dhcp que existen
en la red.

Para que funcione correctamente es necesario tener instalado scapy y el 
tcpdump. Se tiene que ejecutar como root o con sudo.
"""

#Importamos el módulo para hacer llamadas al sistema
#from scapy.all import *
from scapy import conf, get_if_raw_hwaddr, srp
from scapy import Ether, IP, DHCP, UDP, BOOTP
import sys
from optparse import OptionParser



NAGIOS_CODES_STATUS = { 'OK':0,
                        'WARNING':1,
                        'CRITICAL':2,
                        'UNKNOWN':3,
                        'DEPENDENT':4}

OUR_DHCP_SERVER = { 'IP':"192.168.2.254",
        'MAC':"00:15:17:5E:BC:BC"}

def nagios_return( code, message):
    "Función encargada de retornar los valores para el Nagios"
    print code + ": " + message
    sys.exit(NAGIOS_CODES_STATUS[code])


#def parse_data( data ):

    
def get_dhcps_info():
    """ 
    Función que obtiene la información del los servidores de dhcp que existen.
    """
   
    dhcp_servers = {} # Diccionario donde voy a meter toda la info que me sea útil
    server = {}     # 
    tiempo = 2      #Segundos que queremos que realice la búsqueda
    detalle = 0     #Nivel de información suministrada
    conf.checkIPaddr = False
    fam, hwd = get_if_raw_hwaddr(conf.iface)
    dhcp_discover = Ether(dst="ff:ff:ff:ff:ff:ff")/\
        IP(src="0.0.0.0",dst="255.255.255.255")/\
        UDP(sport=68,dport=67)/BOOTP(chaddr=hwd)/\
        DHCP(options=[("message-type","discover"), "end"])
    ans, unans = srp(dhcp_discover, multi=True, timeout=tiempo, verbose=detalle)      
    dhcp_servers['numero'] = len(ans) #Obtenemos el número de servidores de dhcp existentes
    dhcp_servers['servidores'] = {}    
    for val in ans:
        dhcp_servers['servidores'][val[1][IP].src] = {} 
        dhcp_servers['servidores'][val[1][IP].src]['MAC'] = val[1][Ether].src.upper()
        
        for opt in val[1][DHCP].options:
            if opt == 'end':
                break
            elif opt == 'pad':
                break
            elif len(opt) == 2:
                dhcp_servers['servidores'][val[1][IP].src][opt[0]] = opt[1]
            elif len(opt) == 3:
                dhcp_servers['servidores'][val[1][IP].src][opt[0]] = opt[1] +' '+opt[2]
    
    return dhcp_servers


def check_data_nagios( dhcp_servers ):
    """ Función que verifica que estén correctos los parámetros recibidos
    y presenta una salida para el Nagios.
    Si existe sólo un servidor de DHCP y tiene la MAC e IP de nuestro 
    servidor -> OK
    Resto de situaciones -> CRITICO
    """

    if ((dhcp_servers['numero'] == 1) and 
        (OUR_DHCP_SERVER['IP'] in dhcp_servers['servidores']) and
        OUR_DHCP_SERVER['MAC'].upper() == dhcp_servers['servidores'][OUR_DHCP_SERVER['IP']]['MAC'].upper()):
        nagios_return('OK','IP:' + OUR_DHCP_SERVER['IP'] +
                        ' - MAC: ' + OUR_DHCP_SERVER['MAC'].upper() ) 
    #En estado de fallo
    else:
        nagios_msg ="Servidores: " + str(dhcp_servers['numero']) +" ->"
        for key in dhcp_servers['servidores']: 
            nagios_msg += ' ' +  str(key) + ' ' + str(dhcp_servers['servidores'][key]['MAC']) + ';'
        nagios_return('CRITICAL', nagios_msg)

def pretty_print( dhcp_servers ):
    """ Función que saca de forma bonita la información de los servidores encontrados """
    print "\n------------- Información obtenida -------------\n"
    print "Número de servidores DHCP: " + str(dhcp_servers['numero']) + "\n"
    for key1 in dhcp_servers['servidores']:
        print "Servidor: " + key1
        for key2 in dhcp_servers['servidores'][key1]:
            print "\t" + str(key2) + ': ' + str(dhcp_servers['servidores'][key1][key2])
        print "\n"
def main():
    """ 
    Función general
    """
    parser = OptionParser()
    parser.add_option("-n", 
            action = "store_true",
            dest = "nagios",
            help = u"Activa la salida para el Nagios",
            default = False) 

    #Obtenemos los argumentos de entrada
    (options, args) = parser.parse_args()

    if options.nagios == True:
        check_data_nagios(get_dhcps_info())

    else:
        pretty_print(get_dhcps_info())

if __name__ == "__main__":
    main()


__version__ = "$Revision$"
# $Source$

